﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using System.IO;
using MeizuSDK.Drawing;

namespace MeizuSDK.Presentation
{
    /// <summary>
    /// 标签控件
    /// </summary>
    public class Label : Control
    {
        #region DllImport
        [DllImport("MZFCWrapper.dll")]
        private static extern IntPtr UiStaticWrapperCtor(PaintWinFunc paintWin);

        [DllImport("MZFCWrapper.dll")]
        private static extern void UiStaticWrapperDispose(IntPtr handle);

        [DllImport("MZFCWrapper.dll")]
        private static extern void UiStaticWrapperDefaultPaintWin(IntPtr handle, IntPtr hdc, ref RECT prcWin, ref RECT prcUpdate);
        #endregion

        #region 常量
        /// <summary>
        /// 标签控件默认宽度
        /// </summary>
        public const int WIDTH = MzMetrics.MZM_WIDTH_SINGLEEDIT_LONG;
        /// <summary>
        /// 标签控件默认高度
        /// </summary>
        public const int HEIGHT = MzMetrics.MZM_HEIGHT_SINGLELINE_EDIT;
        /// <summary>
        /// 文本与标签边框的边距
        /// </summary>
        public const int TextMargin = 20;
        /// <summary>
        /// 标签控件中文本行间距
        /// </summary>
        public const int LineSpace = 10;
        #endregion

        #region 私有变量
        /// <summary>
        /// 控件自绘委托
        /// </summary>
        private PaintWinFunc paintWinFunc;
        /// <summary>
        /// 标签文本
        /// </summary>
        private string text = string.Empty;
        /// <summary>
        /// 标签是否根据内容自动调整大小
        /// </summary>
        private bool autoSize;
        /// <summary>
        /// 标签内容绘制缓存
        /// </summary>
        private Bitmap bmpLabel;
        /// <summary>
        /// 进行处理并换行的文本
        /// </summary>
        private List<string> wrappedText;
        /// <summary>
        /// 每行文本的高度
        /// </summary>
        private int linetHeight;
        /// <summary>
        /// 标签文本对齐方式
        /// </summary>
        private MeizuSDK.Drawing.ContentAlignment txtAlign;
        /// <summary>
        /// 控件字体
        /// </summary>
        private Font font;
        #endregion

        #region 受保护属性
        /// <summary>
        /// 获取或设置标签绘制缓存
        /// </summary>
        protected Bitmap DrawBuffer
        {
            get
            {
                if (this.bmpLabel == null)
                {
                    this.bmpLabel = new Bitmap(Width, Height);
                }
                return this.bmpLabel;
            }
            set
            {
                if (this.bmpLabel != value)
                {
                    this.bmpLabel = value;
                }
            }
        }
        /// <summary>
        /// 获取进行过处理的换行文本列表
        /// </summary>
        protected List<string> WrappedText
        {
            get
            {
                if (this.wrappedText == null)
                {
                    this.wrappedText = new List<string>();
                }
                return wrappedText;
            }
        }
        #endregion

        #region 公共属性
        /// <summary>
        /// 获取或设置一个标志，指示标签控件是否支持根据文本内容自动缩放
        /// </summary>
        public bool AutoSize
        {
            get
            {
                return this.autoSize;
            }
            set
            {
                if (value != this.autoSize)
                {
                    this.autoSize = value;
                    if (this.autoSize)
                        AutoResizeControl();
                }
            }
        }
        /// <summary>
        /// 获取或设置标签控件显示的文本
        /// </summary>
        public override string Text
        {
            get
            {
                if (!OwnerDraw)
                {
                    this.text = base.Text;
                }
                return this.text;
            }
            set
            {
                if (value != this.text)
                {
                    if (!OwnerDraw)
                    {
                        base.Text = value;
                    }
                    else
                    {
                        this.text = value;
                    }

                    AutoResizeControl();
                }
            }
        }
        /// <summary>
        /// 获取或设置文本在标签控件中的对齐方式
        /// </summary>
        public MeizuSDK.Drawing.ContentAlignment TextAlign
        {
            get
            {
                return this.txtAlign;
            }
            set
            {
                if (value != this.txtAlign)
                {
                    this.txtAlign = value;
                    Invalidate();
                    Update();
                }
            }
        }
        #endregion

        #region 构造函数
        /// <summary>
        /// 构造标签控件对象
        /// </summary>
        public Label()
        {
            paintWinFunc = new PaintWinFunc(InternalPaintWin);

            Handle = UiStaticWrapperCtor(paintWinFunc);
            SetID();
            Size = new Size(WIDTH, HEIGHT);
            OwnerDraw = true;// 标签控件自绘
            bmpLabel = new Bitmap(WIDTH, HEIGHT);// 生成绘制缓存
            txtAlign = MeizuSDK.Drawing.ContentAlignment.MiddleCenter;// 文本对齐方式
        }
        #endregion

        #region 函数
        /// <summary>
        /// 自动重新调成控件大小
        /// </summary>
        private void AutoResizeControl()
        {
            if (autoSize)
            {
                WrappedText.Clear();

                Size txtSize = GetTextSize();

                Size = new Size(txtSize.Width + TextMargin * 2, txtSize.Height + TextMargin * 2);
            }

            // 重绘标签
            Invalidate();
            Update();
        }
        /// <summary>
        /// 获取文本所在区域的大小。已经包含行高，不包含文本与边框的边距
        /// </summary>
        /// <returns></returns>
        private Size GetTextSize()
        {
            Size txtSize = Size.Empty;

            IntPtr hdc = NativeMethods.GetDC(IntPtr.Zero);
            if (hdc != IntPtr.Zero)
            {
                using (Graphics g = Graphics.FromHdc(hdc))
                {
                    string[] segements = Text.Split('\r', '\n');

                    int height = 0;
                    int width = 0;

                    for (int i = 0; i < segements.Length; i++)
                    {
                        SizeF lineSize = g.MeasureString(segements[i], Font);

                        if (i % 2 == 0)
                            height += (int)lineSize.Height + LineSpace;
                        else
                            height += (int)lineSize.Height;

                        // 行高
                        linetHeight = Math.Max(linetHeight, (int)lineSize.Height);

                        width = Math.Max(width, (int)lineSize.Width);

                        // 换行
                        WrappedText.Add(segements[i]);
                    }

                    txtSize = new Size(width, height);
                    try
                    {
                        g.ReleaseHdc(hdc);
                    }
                    catch (Exception) { }
                }
            }

            return txtSize;
        }
        /// <summary>
        /// 系统默认绘制方法
        /// </summary>
        /// <param name="hdcDst"></param>
        /// <param name="prcWin"></param>
        /// <param name="prcUpdate"></param>
        protected override void OnDefaultPaintWin(IntPtr hdcDst, ref RECT prcWin, ref RECT prcUpdate)
        {
            try
            {
                UiStaticWrapperDefaultPaintWin(Handle, hdcDst, ref prcWin, ref prcUpdate);
            }
            catch (Exception) { }
        }
        /// <summary>
        /// 获取文本绘制是所需的文本布局信息
        /// </summary>
        /// <returns></returns>
        protected StringFormat GetStringFormat()
        {
            StringFormat sf = new StringFormat(StringFormatFlags.NoClip);

            switch (TextAlign)
            {
                case MeizuSDK.Drawing.ContentAlignment.TopLeft:
                    {
                        sf.Alignment = StringAlignment.Near;
                        sf.LineAlignment = StringAlignment.Near;
                    }
                    break;
                case MeizuSDK.Drawing.ContentAlignment.TopCenter:
                    {
                        sf.Alignment = StringAlignment.Center;
                        sf.LineAlignment = StringAlignment.Near;
                    }
                    break;
                case MeizuSDK.Drawing.ContentAlignment.TopRight:
                    {
                        sf.Alignment = StringAlignment.Far;
                        sf.LineAlignment = StringAlignment.Near;
                    }
                    break;
                case MeizuSDK.Drawing.ContentAlignment.MiddleLeft:
                    {
                        sf.Alignment = StringAlignment.Near;
                        sf.LineAlignment = StringAlignment.Center;
                    }
                    break;
                case MeizuSDK.Drawing.ContentAlignment.MiddleCenter:
                    {
                        sf.Alignment = StringAlignment.Center;
                        sf.LineAlignment = StringAlignment.Center;
                    }
                    break;
                case MeizuSDK.Drawing.ContentAlignment.MiddleRight:
                    {
                        sf.Alignment = StringAlignment.Far;
                        sf.LineAlignment = StringAlignment.Center;
                    }
                    break;
                case MeizuSDK.Drawing.ContentAlignment.BottomLeft:
                    {
                        sf.Alignment = StringAlignment.Near;
                        sf.LineAlignment = StringAlignment.Far;
                    }
                    break;
                case MeizuSDK.Drawing.ContentAlignment.BottomCenter:
                    {
                        sf.Alignment = StringAlignment.Center;
                        sf.LineAlignment = StringAlignment.Far;
                    }
                    break;
                case MeizuSDK.Drawing.ContentAlignment.BottomRight:
                    {
                        sf.Alignment = StringAlignment.Far;
                        sf.LineAlignment = StringAlignment.Far;
                    }
                    break;
            }

            return sf;
        }
        /// <summary>
        /// 绘制控件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaintWin(PaintEventArgs e)
        {
            if (!Visible || !OwnerDraw)
                return;

            if (!AutoSize)
            {
                WrappedText.Clear();
                WrappedText.Add(Text);
            }

            using (Graphics g = e.Graphics)
            {
                // 起始点
                Point startPoint = new Point(e.ClientRectangle.X + TextMargin, e.ClientRectangle.Y + TextMargin);

                using (StringFormat sf = GetStringFormat())
                {
                    using (SolidBrush brush = new SolidBrush(ForeColor))
                    {
                        for (int i = 0; i < WrappedText.Count; i++)
                        {
                            Rectangle lineRect = new Rectangle(startPoint.X, startPoint.Y + (i * linetHeight + (i % 2 == 0 ? LineSpace : 0)),
                                e.ClientRectangle.Width - TextMargin * 2, linetHeight);
                            g.DrawString(WrappedText[i], Font, brush, lineRect, sf);
                        }
                    }
                }
            }

            base.OnPaintWin(e);
        }
        /// <summary>
        /// 销毁资源
        /// </summary>
        /// <param name="disposing"></param>
        protected override void Dispose(bool disposing)
        {
            try
            {
                if (font != null)
                    font.Dispose();

                if (bmpLabel != null)
                    bmpLabel.Dispose();
            }
            catch (Exception) { }

            base.Dispose(disposing);
        }
        #endregion
    }
}
